Go: syscall/js: Add Truthy() and Falsy() to Value methods

Created on 18 Oct 2018  路  15Comments  路  Source: golang/go

What version of Go are you using (go version)?

go version go1.11 darwin/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

js/wasm


JS has the concept of "truthy" and "falsy". It'd be nice if these were part of syscall/js, either as part and parcel of Value.Bool(), or failing that something along the lines of

func (o Value) Falsy() bool {
    return !o.Truthy()
}

func (o Value) Truthy() bool {
    switch o.Type() {
    case TypeUndefined, TypeNull:
        return false
    case TypeBoolean:
        return o.Bool()
    case TypeNumber:
        if math.IsNaN(o.Float()) {
            return false
        }
        return o.Float() != 0
    case TypeString:
        return o.String() != ""
    case TypeSymbol, TypeObject, TypeFunction:
        return true
    }
    return true
}
Arch-Wasm FeatureRequest FrozenDueToAge NeedsDecision

Most helpful comment

I suspect that a pure-Go version would be faster and just as accurate as trampolining to JavaScript.

It might be useful to have some hard numbers here. It seems like a lot of work is being done to speed up these types of calls.

All 15 comments

/cc @neelance

I'm not yet sure if it would be good to include it in syscall/js. For which APIs would you need the concept of "truthy"? Could you provide examples please?

I've been updating my Vue.js wrapper to use your wasm-sync-callbacks tree. I was trying to replicate an example from the Vue Guide (here, the bit that starts with "This will render the same result. We can also bind to a computed property that returns an object.") The JS in question is

function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
}

So for this.isActive and this.error I wanted "truthy", for !this.error I wanted "falsy". I implemented that part of that example like this:

return hvue.Map2Obj(hvue.M{
    "active": hvue.Truthy(data3.Get("isActive")) &&
        hvue.Falsy(data3.Get("error")),
    "text-danger": hvue.Truthy(data3.Get("error")) &&
        data3.Get("error").Get("type").String() == "fatal",
})

where hvue.Map2Obj(hvue.M{...}) is similar to how GopherJS automagically transforms a GopherJS js.M{} into a JS object, and hvue.Truthy() and Falsy() are similar to the example code I posted at the top of this issue, except obviously not methods on js.Value. (See here.)

One could certainly argue that the _absence_ of such a vague concept as "truthiness" in Go is (one of the reasons) _why we use Go_ and not JavaScript, and I could certainly understand that, and agree that in most cases you shouldn't do it. But pragmatically I think there are clear use-cases for it.

So to sum up, when transliterating JavaScript to Go, since JavaScript uses truthiness a lot, I think it'd be handy and pragmatic for JS-transliterated-to-Go to be able to do the same, "out of the box".

I could see that you might not want Value.Truthy()/Falsy() in syscall/js (although obviously _I_ think having them as methods on Value would be the most useful). There are other utility-functions that might also be handy, that shouldn't be in syscall/js. So perhaps a syscall/js/jsutil or top-level jsutil package would be appropriate? We discussed this a bit in the Gophers #webassembly channel (starting here), and one library with some nice utilities was pointed out: https://github.com/dennwc/dom/tree/master/js (permalink).

I'm not yet sure if it would be good to include it in syscall/js

I'd tend to agree; the implementation of "truthy" or "falsey" feels like something that should be left to the JavaScript VM; we would be reimplementing that logic which feels wrong.

we would be reimplementing that logic

Not necessarily. It could be

// Global JavaScript function
function isTruthy(o) {
  if (o) { return true } else { return false }
  // or even: return !!o
}
func (o Value) Truthy() bool {
   return Global().Call("isTruthy", o).Bool()
}

That said, the concept of "truthy", while admittedly a bit general, is actually pretty well-defined: "All values are truthy unless they are defined as falsy (i.e., except for false, 0, "", null, undefined, and NaN)". (In fact in my initial implementation of Truthy() & Falsy() I had Falsy() checking for false/0/etc, and Truthy was !Falsy, but then I inverted them.) My point being, I suspect that a pure-Go version would be faster and just as accurate as trampolining to JavaScript.

I suspect that a pure-Go version would be faster and just as accurate as trampolining to JavaScript.

It might be useful to have some hard numbers here. It seems like a lot of work is being done to speed up these types of calls.

It might be useful to have some hard numbers here

Happy to give it a shot, if @neelance (et al) think this is a reasonable feature in the first place. If they don't want to do it, it doesn't matter how fast it is. :)

If the JS-inclined people generally agree this is a good idea, I don't object to adding one method. Two seems overkill, though. (e.g. we have utf8.ValidString but we don't also have utf8.InvalidString for the opposite)

I am quite sure that the pure-Go version will be faster.

In JS, using truthiness is common, but I think this is mostly because it has the simplest syntax. Not using truthiness in JS just looks ugly quite often.

I've seen truthiness hiding bugs. Having a strong expectation about a type of a value is usually safer. However, there are use cases with legacy code that need truthiness.

I don't object to adding just Truthy either. I just hope it will get used sparingly.

I think in the case of porting legacy JS into a Go ecosystem, the Truthiness concept and the need to port this behaviour would appear often, and could be a point of confusion and or bugs.

In the interests of correctness on the Go side of the fence, it would be good if syscall/js provided a correct implementation for all to use, and make porting that little bit more attractive.

Having said that, I hope that I _never ever_ have the need to use this syscall myself.

I am slightly leaning in favor of this. I suspect more people will ask for this as wasm gains in popularity. I would also prefer a pure-Go version since truthy-ness is quite well-defined.

@theclapp Mind creating a CL? :)

@neelance Will do. It may be a few days. This'll be my first Go code contribution, so there's that first-timer learning curve to climb.

Change https://golang.org/cl/144384 mentions this issue: syscall/js: add Truthy() as a method on js.Value

Change https://golang.org/cl/154618 mentions this issue: doc/go1.12: add notes for syscall/js CLs 141644, 143137, 144384

Was this page helpful?
0 / 5 - 0 ratings