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

syscall/js: possibility of using String.prototype.* methods on strings #35917

Closed
dmitshur opened this issue Dec 1, 2019 · 5 comments
Closed
Labels
arch-wasm WebAssembly issues FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@dmitshur
Copy link
Contributor

dmitshur commented Dec 1, 2019

With GopherJS, it was possible to call the String.prototype.toLowerCase method on a JavaScript String:

https://gopherjs.github.io/playground/#/ekZpm7tuW4

It's possible I'm overlooking something trivial, but this doesn't seem possible with syscall/js API of WebAssembly. Consider the same program modified to use syscall/js:

package main

import (
	"fmt"
	"syscall/js"
)

func main() {
	body := js.Global().Get("document").Get("body")

	fmt.Println(body.Get("nodeName"))
	fmt.Println(body.Get("nodeName").Call("toLowerCase"))
	fmt.Println(body.Get("nodeName").Get("toLowerCase").Invoke())
}

Its output with Go 1.13.4 is:

BODY
panic: syscall/js: call of Value.Get on string

goroutine 1 [running]:
syscall/js.Value.Get(0x7ff800010000000e, 0x34d12, 0xb, 0x7ff800010000000e)
	/usr/local/go/src/syscall/js/js.go:252 +0x39
main.main()
	/tmp/tmp.CQimpW7L/main.go:12 +0xb

Depending on whether a JavaScript String type is considered a "JavaScript object" or not, this may be consistent with js.Value.Get documentation, which says:

Get returns the JavaScript property p of value v. It panics if v is not a JavaScript object.

I'm wondering if it's possible to use toLowerCase with syscall/js API? If not, should it be possible?

/cc @neelance

@dmitshur dmitshur added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. arch-wasm WebAssembly issues labels Dec 1, 2019
@dmitshur dmitshur added this to the Backlog milestone Dec 1, 2019
@slimsag
Copy link

slimsag commented Dec 1, 2019

Workaround: you can call JS String methods via the String.prototype itself, i.e. in JS:

String.prototype.toLowerCase.call("FOO")

In Go:

js.Global().Get("String").Get("prototype").Get("toLowerCase").Call("call", js.ValueOf("FOO"))

I have used this in hexops/vecty#251 in order to workaround this problem.

@agnivade
Copy link
Contributor

agnivade commented Dec 1, 2019

If not, should it be possible?

I think it should. The current API relies on Reflect.get which only works on objects, and therefore fails on normal strings. With a little bit of code, and now with the argument spread syntax available, I was able to make it work.

fmt.Println(body.Get("nodeName").Call("toLowerCase"))
fmt.Println(body.Get("nodeName").Call("charAt", 3))

Not pasting the code here. But I can send a CL if Richard is okay with it.

@neelance
Copy link
Member

neelance commented Dec 1, 2019

This is because of JavaScript's autoboxing. string and String are two distinct types. The first is the primitive type, the second one is the boxed object type and only the second has methods. Autoboxing makes it so the expression

"foo".toUpperCase()

gets interpreted as

new String("foo").toUpperCase()

I do not yet see why syscall/js should emulate autoboxing. Is there any proper use case? In my opinion, for the examples above the proper solution is to use the .String() method to get the Go string and then use Go's functions for manipulating the string.

@dmitshur
Copy link
Contributor Author

dmitshur commented Dec 1, 2019

Thanks for the explanation.

I do not yet see why syscall/js should emulate autoboxing.

I agree, I don't think that would be a good change.

In my opinion, for the examples above the proper solution is to use the .String() method to get the Go string and then use Go's functions for manipulating the string.

It should also be possible to use JavaScript's toLowerCase explicitly, if one wants to (e.g., to avoid having to import strings package, or for other JavaScript functions where there isn't equivalent Go functionality).

It sounds like it is possible with one of these two ways:

var str string = "FOO"

js.Global().Get("String").New(str).Call("toLowerCase")

// or

js.Global().Get("String").Get("prototype").Get("toLowerCase").Call("call", str)

So nothing needs to be done. I'll close this if there aren't objections.

@agnivade
Copy link
Contributor

agnivade commented May 8, 2020

It looks like there are no objections. ping @dmitshur.

@golang golang locked and limited conversation to collaborators Oct 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
arch-wasm WebAssembly issues FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants