Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to call JS functions with more than 2 arguments in Embedded Swift #279

Open
ole opened this issue Jan 13, 2025 · 2 comments · May be fixed by #281
Open

Unable to call JS functions with more than 2 arguments in Embedded Swift #279

ole opened this issue Jan 13, 2025 · 2 comments · May be fixed by #281

Comments

@ole
Copy link
Contributor

ole commented Jan 13, 2025

When building for Embedded Swift, JSValue and JSObject don’t support JS function calls with more than 2 arguments. I noticed this when trying to call the fillRect() method on CanvasRenderingContext2D. Example:

import JavaScriptKit

let document = JSObject.global.document
let canvas = document.getElementById("canvas")
var ctx: JSValue = canvas.getContext("2d")
// 🔴 Error (in Embedded Swift only): cannot call value of non-function type 'JSValue'
_ = ctx.fillRect(20, 20, 200, 100)

The following works as a workaround but is ugly:

_ = ctx.object!.fillRect.function!(this: ctx.object!, arguments: [20, 20, 200, 100])

The reason that it doesn't work is:

  1. Embedded Swift doesn't support existentials, so the general function invocation mechanism of the form subscript(dynamicMember name: String) -> ((ConvertibleToJSValue...) -> JSValue) is not available.

  2. Both JSValue and JSObject only have concrete overloads for up to 2 function call arguments:

    #if hasFeature(Embedded)
    public extension JSValue {
        @_disfavoredOverload
        subscript(dynamicMember name: String) -> (() -> JSValue)
    
        @_disfavoredOverload
        subscript<A0: ConvertibleToJSValue>(dynamicMember name: String) -> ((A0) -> JSValue)
    
        @_disfavoredOverload
        subscript<A0: ConvertibleToJSValue, A1: ConvertibleToJSValue>(dynamicMember name: String) -> ((A0, A1) -> JSValue)
    }
    #endif

Question: Would you be interested in a PR that adds more of these concrete overloads for Embedded Swift? Or do you want to wait for variadic generics support in Embedded Swift to solve this problem "the right way"?

If it's the former, I'm willing to send the PR. In this case, up to how many arguments should I go? Is 4 enough? Or should we go up to, say, 6?

@kateinoigakukun
Copy link
Member

It's fine to add more overloads until parameter packs will be available in Embedded mode.

@ole
Copy link
Contributor Author

ole commented Jan 13, 2025

Great! I'll send a PR soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants