jsii icon indicating copy to clipboard operation
jsii copied to clipboard

Python: sync vs async return different objects but same type-hint

Open TomBonnerAtDerivitec opened this issue 2 years ago • 3 comments

Describe the bug

The type-hint provided to Python is the same between synchronous requests, and asynchronous requests. However the returned type for a synchronous request is a value-type, but the asynchronous is a reference-type.

Expected Behavior

I would expect the type-hinting to match the actual returned type, and would personally always prefer value-types given I can't work out how to get data from the reference-types.

Current Behavior

The type-hint for sync and async requests is the same, but in actuality one is a value-type and the other is a reference-type.

Reproduction Steps

The TypeScript side looks like this:

export interface Record {
    readonly name: string;
}

export class RecordFactory {

    public makeRecord(): Record {

        return {
            name: "Record A"
        }
    }

    public async makeRecordAsync(): Promise<Record> {

        return new Promise(res => {
            setTimeout(() => {
                res({
                    name: "Record B"
                })
            }, 1000);
        });
    }
}

The Python side looks like this:

record_factory = RecordFactory()

record = record_factory.make_record()
record_async = record_factory.make_record_async()

print(record.name)
print(record_async.name)

This would throw an error on the second print because record_async.name does not exist, because record_async is a reference-type.

The generated Python library looks like this:

class RecordFactory(metaclass=jsii.JSIIMeta, jsii_type="jsii-test.RecordFactory"):
    def __init__(self) -> None:
        jsii.create(self.__class__, self, [])

    @jsii.member(jsii_name="makeRecord")
    def make_record(self) -> Record:
        return typing.cast(Record, jsii.invoke(self, "makeRecord", []))

    @jsii.member(jsii_name="makeRecordAsync")
    def make_record_async(self) -> Record:
        return typing.cast(Record, jsii.ainvoke(self, "makeRecordAsync", []))

Possible Solution

I'm just investigating JSII as a solution for an issue we have, so don't know what the solution is here. What I can say is this is confusing for a new user. The way I see it either the return type for the async function should be either swapped to show the reference type, or better yet (IMHO) could correctly cast to a value-type.

Additional Information/Context

No response

SDK version used

1.61.0

Environment details (OS name and version, etc.)

Mac-OS, Node 17, TS 3.9.10

TomBonnerAtDerivitec avatar Jun 27 '22 10:06 TomBonnerAtDerivitec

I have checked the dotNet generated package as well which worked as expected:

var recordFactory = new RecordFactory();

var record = recordFactory.MakeRecord();
var recordAsync = recordFactory.MakeRecordAsync();

Console.WriteLine($"Sync-record: {record.Name}");
Console.WriteLine($"Async-record: {recordAsync.Name}");

Output:

Sync-record: Record A
Async-record: Record B

TomBonnerAtDerivitec avatar Jun 27 '22 10:06 TomBonnerAtDerivitec

Additionally, if I return as a Promise<any> it correctly works as an async but doesn't have type-hinting.

TomBonnerAtDerivitec avatar Jun 27 '22 11:06 TomBonnerAtDerivitec

Ah - I guess the compiler & doc should call this out clearly, but async support is largely untested and not very uniformly implemented... we never really had a clear use-case for this, and async/await semantics aren't available consistently in our target runtimes, which creates additional headaches in figuring out how to consistently represent...

I believe the .NET solution "works", although it most likely runs pseudo-synchronously, in fact...

I'd be inclined to actually fix that (granted you appear to have a use-case), but I'm afraid it might take a while before we can prioritize this specifically.

RomainMuller avatar Aug 02 '22 08:08 RomainMuller

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] avatar Nov 23 '22 13:11 github-actions[bot]